﻿using Group3.MediaTool.Core.ObjectGenerator;
using Group3.MediaTool.Data.Generator;
using Group3.MediaTool.Data.IO;
using Group3.MediaTool.Generator;
using Group3.MediaTool.Interface;
using Group3.MediaTool.Provider;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Group3.MediaTool.UnitTests
{
    [TestClass]
    public class ClassBuilderTest
    {
        [TestMethod]
        public void BuildClassTest()
        {
            ClassBuilder cb = new ClassBuilder();


            IObjectDefinition def = new Core.ObjectGenerator.ObjectDefinition();

            def.DataFields = new List<IFieldDefinition>() { new FieldDefinition() { FieldName = "Test", ValueType = e_ValueType.Relation }, new FieldDefinition() { FieldName = "Test2", ValueType = e_ValueType.Boolean } };
            def.OrmName = "Test1";
            cb.BuildClass(def);
            //The ObjectProvider loads the new generated Class into the testapplication and can now be used in it.
            ObjectProvider.Instance = new ObjectProvider();
            ObjectProvider.Instance.DoImport();
            Assert.IsNotNull(ObjectProvider.Instance.ProvidedObjects.FirstOrDefault());

        }

        [TestMethod]
        public void InterActWithTest()
        {
            ClassBuilder cb = new ClassBuilder();


            IObjectDefinition def = new Core.ObjectGenerator.ObjectDefinition();

            def.DataFields = new List<IFieldDefinition>() { new FieldDefinition() { FieldName = "Test", ValueType = e_ValueType.String } };
            def.OrmName = "Test2";
            cb.BuildClass(def);
            //The ObjectProvider loads the new generated Class into the testapplication and can now be used in it.
            ObjectProvider.Instance = new ObjectProvider();
            ObjectProvider.Instance.DoImport();
            Assert.IsNotNull(ObjectProvider.Instance.ProvidedObjects.FirstOrDefault());
            var test = ObjectProvider.Instance.ProvidedObjects.Where(o=>o.GetType().Name == "E_Test2").FirstOrDefault();
            var props = test.GetPropertyNames();
            foreach (var s in props)
            {
                Assert.IsTrue(test.SetValue(s, "Test"));
                Assert.AreEqual(test.GetValue(s), "Test");
            }
            ObjectProvider.Instance.DoReleaseExport("E_Test2");
        }

        [TestMethod]
        public void WriteAndRead()
        {
            ClassBuilder cb = new ClassBuilder();
            StaticConfig.Database = e_DataStoreProvider.NDatabase;

            IObjectDefinition def = new Core.ObjectGenerator.ObjectDefinition();

            def.DataFields = new List<IFieldDefinition>() { new FieldDefinition() { FieldName = "Test", ValueType = e_ValueType.String } };
            def.OrmName = "Test3";
            cb.BuildClass(def);
            //The ObjectProvider loads the new generated Class into the testapplication and can now be used in it.
            ObjectProvider.Instance = new ObjectProvider();
            ObjectProvider.Instance.DoImport();
            Assert.IsNotNull(ObjectProvider.Instance.ProvidedObjects.FirstOrDefault());
            var test = ((IObjectRelationModel)ObjectProvider.Instance.ProvidedObjects.Where(o => o.GetType().Name == "E_Test3").FirstOrDefault().Instantiate());
            var props = test.GetPropertyNames();
            foreach (var s in props)
            {
                Assert.IsTrue(test.SetValue(s, "Test"));
                Assert.AreEqual(test.GetValue(s), "Test");
            }
            test.Write();
            test.SetValue("Test", "TestNachSchreiben");
            Assert.AreEqual(test.GetValue("Test"), "TestNachSchreiben");
            var col = test.ReadAll();
            Assert.IsNotNull(col);
            Assert.AreEqual(col.ElementAt(0).GetValue("Test"), "Test");
            ObjectProvider.Instance.DoReleaseExport("E_Test3");
        }

        [TestMethod]
        public void WriteAndReadWithObserver()
        {
            ClassBuilder cb = new ClassBuilder();
            StaticConfig.Database = e_DataStoreProvider.NDatabase;

            IObjectDefinition def = new Core.ObjectGenerator.ObjectDefinition();

            def.DataFields = new List<IFieldDefinition>() { new FieldDefinition() { FieldName = "Test", ValueType = e_ValueType.String } };
            def.OrmName = "Test4";
            cb.BuildClass(def);
            //The ObjectProvider loads the new generated Class into the testapplication and can now be used in it.
            ObjectProvider.Instance = new ObjectProvider();
            ObjectProvider.Instance.DoImport();
            Assert.IsNotNull(ObjectProvider.Instance.ProvidedObjects.FirstOrDefault());
            var test = ((IObjectRelationModel)ObjectProvider.Instance.ProvidedObjects.Where(o => o.GetType().Name == "E_Test4").FirstOrDefault().Instantiate());
            string message = "";
            var observer = Group3.MediaTool.Core.Reactive.EntityObserver.CreateEntityObserver("testAction", () => { message = "Done"; }, (ex) => { message = "Error"; }, (v) => { message = "change"; });
            //Subscribe to observer
            ((IObservable<IObjectRelationModel>)test).Subscribe(observer);
            var props = test.GetPropertyNames();
            foreach (var s in props)
            {
                Assert.IsTrue(test.SetValue(s, "Test"));
                Assert.AreEqual(test.GetValue(s), "Test");
            }
            Assert.AreEqual(message, "change");
            test.Write();
            test.SetValue("Test", "TestNachSchreiben");
            Assert.AreEqual(test.GetValue("Test"), "TestNachSchreiben");
            var col = test.ReadAll();
            Assert.IsNotNull(col);
            Assert.AreEqual(col.ElementAt(0).GetValue("Test"), "Test");

            ObjectProvider.Instance.DoReleaseExport("E_Test4");
        }

        [TestMethod]
        public void LoadClassesAndAddOneAfterwards()
        {
            //Delete E_Test5.dll if exists
            //string path = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Classes\\E_Test5.dll");
            string path = System.IO.Path.Combine(StaticConfig.pathDataDefinition, "Classes\\E_Test5.dll");
            if (System.IO.File.Exists(path))
                System.IO.File.Delete(path);
            ClassBuilder cb = new ClassBuilder();

            ObjectProvider.Instance = new ObjectProvider();
            ObjectProvider.Instance.DoImport();
            IObjectDefinition def = new Core.ObjectGenerator.ObjectDefinition();

            def.DataFields = new List<IFieldDefinition>() { new FieldDefinition() { FieldName = "Test", ValueType = e_ValueType.String } };
            def.OrmName = "Test5";
            cb.BuildClass(def);
            //The ObjectProvider loads the new generated Class into the testapplication and can now be used in it.

            Assert.IsNotNull(ObjectProvider.Instance.ProvidedObjects.FirstOrDefault());

            ObjectProvider.Instance.DoReleaseExport("E_Test5");
            ObjectProvider.Instance.DoImport();
            Assert.IsNotNull(ObjectProvider.Instance.ProvidedObjects.FirstOrDefault());

            var test = ((IObjectRelationModel)ObjectProvider.Instance.ProvidedObjects.Where(o => o.GetType().Name == "E_Test5").FirstOrDefault().Instantiate());
            Assert.IsNotNull(test);


        }

        [TestMethod]
        public void LoadClassesAndDeleteAfterwards()
        {
            //Delete E_Test5.dll if exists
            //string path = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Classes\\E_Test6.dll");
            string path = System.IO.Path.Combine(StaticConfig.pathDataDefinition, "Classes\\E_Test6.dll");
            if (System.IO.File.Exists(path))
                System.IO.File.Delete(path);

            //Setup AppDomain
            

            ClassBuilder cb = new ClassBuilder();

            ObjectProvider.Instance = new ObjectProvider();
            IObjectDefinition def = new Core.ObjectGenerator.ObjectDefinition();

            def.DataFields = new List<IFieldDefinition>() { new FieldDefinition() { FieldName = "Test", ValueType = e_ValueType.String } };
            def.OrmName = "Test6";
            cb.BuildClass(def);
            //The ObjectProvider loads the new generated Class into the testapplication and can now be used in it.
            ObjectProvider.Instance.DoImport();
            Assert.IsNotNull(ObjectProvider.Instance.ProvidedObjects.FirstOrDefault());

            var test = ((IObjectRelationModel)ObjectProvider.Instance.ProvidedObjects.Where(o => o.GetType().Name == "E_Test6").FirstOrDefault().Instantiate());
            Assert.IsNotNull(test);

            ObjectProvider.Instance.DoReleaseExport("E_Test6");
            Assert.IsTrue(!System.IO.File.Exists(path));
        }
        [TestMethod]
        public void LoadClassesAndChangeAfterwards()
        {
            //Delete E_Test5.dll if exists
            //string path = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Classes\\E_Test6.dll");
            string path = System.IO.Path.Combine(StaticConfig.pathDataDefinition, "Classes\\E_Test6.dll");
            if (System.IO.File.Exists(path))
                System.IO.File.Delete(path);

            //Setup AppDomain
            ClassBuilder cb = new ClassBuilder();

            ObjectProvider.Instance = new ObjectProvider();
            IObjectDefinition def = new Core.ObjectGenerator.ObjectDefinition();

            def.DataFields = new List<IFieldDefinition>() { new FieldDefinition() { FieldName = "Test", ValueType = e_ValueType.String } };
            def.OrmName = "Test6";
            cb.BuildClass(def);
            //The ObjectProvider loads the new generated Class into the testapplication and can now be used in it.
            ObjectProvider.Instance.DoImport();
            Assert.IsNotNull(ObjectProvider.Instance.ProvidedObjects.FirstOrDefault());

            var test = ((IObjectRelationModel)ObjectProvider.Instance.ProvidedObjects.Where(o => o.GetType().Name == "E_Test6").FirstOrDefault().Instantiate());
            Assert.IsNotNull(test);

            ObjectProvider.Instance.DoReleaseExport("E_Test6");
            Assert.IsTrue(!System.IO.File.Exists(path));
            def.DataFields = new List<IFieldDefinition>() { new FieldDefinition() { FieldName = "Test2", ValueType = e_ValueType.String } };
            def.OrmName = "Test6";
            cb.BuildClass(def);
            ObjectProvider.Instance.DoReImport();
            test = ((IObjectRelationModel)ObjectProvider.Instance.ProvidedObjects.Where(o => o.GetType().Name == "E_Test6").FirstOrDefault().Instantiate());
            Assert.IsNotNull(test);

        }
    }
}
